package com.kfm.am;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class DBUtils {

    private Connection conn;
    private PreparedStatement ps;
    private DruidDataSource dataSource;

    // 每次获取连接 创建 PreparedStatement
    // 你提供sql 这个类来执行
    public <E> List<E> select(String sql, Handler<E> handler, Object... params) throws Exception {
        getPs(sql);
        setParams(params);
        // 解析 ResultSet --> List 集合
        ResultSet set = ps.executeQuery();
        List<E> list = new ArrayList<>();
        // 一行数据
//        Object[] objects = new Object[set.getMetaData().getColumnCount()];
        while (set.next()) {
            // 此时 set 代表一行数据  --> 就是一个 Student 对象
//            for (int i = 0; i < objects.length; i ++) {
//                objects[i] = set.getObject(i + 1);
//            }
            E handle = handler.handle(set);
//            E handle = handler.handle(objects);
            // handler.handle(objects) 相当于下面这段话
//            Student student = new Student();
//            student.setId(set.getInt("id"));
//            student.setName(set.getString("name"));
//            student.setBirth(set.getDate("birth"));
//            student.setGender(set.getString("gender"));
            list.add(handle);
//            list.add(student);
        }
        return list;
    }

    public <E> List<E> select(String sql, Class<E> cls, Object... params) throws Exception {
        getPs(sql);
        setParams(params);
        // 解析 ResultSet --> List 集合
        ResultSet set = ps.executeQuery();
        ResultSetMetaData metaData = set.getMetaData();
        int count = metaData.getColumnCount();
        List<E> list = new ArrayList<>();
        while (set.next()) {
            // 通过字节码对象 创建实例对象
            E e = cls.getDeclaredConstructor().newInstance();
            // set 一行数据
            for (int i = 1; i <= count; i++) {
                // 第 i 列的字段名 获取每一列的字段名 （类的成员变量名）
                String columnName = metaData.getColumnName(i);
                Object value = set.getObject(i);
                // 字节码对象.getDeclaredField("成员变量名")  --> 指定成员变量名的 Field 对象
                // 通过 Field 对象的 set 方法可以给对象设置值 set(e, value)
                // cls.getDeclaredField("name")  --> 获取id成员变量的 Field 实例
                Field field = cls.getDeclaredField(columnName);
                field.setAccessible(true);
                field.set(e, value);
            }
            list.add(e);
        }
        return list;
    }

    public <E> E selectOne(String sql, Handler<E> handler, Object... params) throws Exception {
        List<E> select = select(sql, handler, params);
        if (select != null && select.size() > 0) {
            return select.get(0);
        }
        return null;
    }

    public int update(String sql, Object... params) throws Exception {
        getPs(sql);
        setParams(params);
        return ps.executeUpdate();
    }

    private void setParams(Object... params) throws SQLException {
        // 替换占位符
        for (int i = 1; i <= params.length; i++) {
            ps.setObject(i, params[i - 1]);
        }
    }

    public void close() throws SQLException {
        if (ps != null && !ps.isClosed()) {
            ps.close();
            ps = null;
        }
        if (conn != null && !conn.isClosed()) {
            conn.close();
            conn = null;
        }
        if (dataSource != null && !dataSource.isClosed()) {
            dataSource.close();
            dataSource = null;
        }
    }

    // 只需要有一个 Connection
    private void getConnection() throws Exception {
        if (conn == null) {
            // 加载驱动
//            Class.forName("com.mysql.cj.jdbc.Driver");
//            DriverManager.getConnection("");
            getDataSource();
            conn = dataSource.getConnection();
        }
    }

    private void getPs(String sql) throws Exception {
        getConnection();
        ps = conn.prepareStatement(sql);
    }

    private void getDataSource() throws Exception {
        if (dataSource == null) {
            // 加载配置文件 --> Properties
            Properties prop = new Properties();
            prop.load(new FileInputStream("io/datasource.properties"));
            // 通过配置创建 DataSource
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
        }
    }
}

class Test {
    public static void main(String[] args) throws Exception {
        DBUtils dbUtils = new DBUtils();
//        String sql = "select * from student where id = ?";
////        List<Student> list = dbUtils.select("select * from student where id = ?", 1);
//        Student student = dbUtils.selectOne(sql, new Student.StudentHandler(), 1);
////        student.get
//        List<Teacher> teachers = dbUtils.select("select * from teacher", new Handler<Teacher>() {
//            @Override
//            public Teacher handle(ResultSet set) throws SQLException {
//                Teacher teacher = new Teacher();
//                teacher.setTeacherId(set.getInt("teacher_id"));
//                teacher.setTeacherName(set.getString("teacher_name"));
//                return teacher;
//            }
//        });
//        System.out.println(student);
        List<Region> select = dbUtils.select("select * from s_region", Region.class);
        System.out.println(select);
        dbUtils.close();
    }
}
